#!/bin/bash
#THIS DRIVER WRITTEN BY MATTHEW VONA ARB FOR THE TECO MODEL 43i-TLE 
#FOR QUESTIONS WRITE mailto:mvona@arb.ca.gov
#THIS DRIVER IS DEPENDENT UPON THE 'erec' COMMAND OF THE
#TECO RS232 INTERFACE.  WE USED THE DEFAULT CONFIGURATION
#BUT THIS CAN BE MODIFIED.
#UPDATED Thu 12 Nov 2009 02:44:43 PM PST 
#
#-------------------------------------------------------------
#!/usr/bin/env bash
# THIS IS THE FUNCTION CALLED IN THE EVENT THAT CTRL+C IS PRESSED
cleanup()
{
	echo "Caught Signal ... cleaning up."
	#cat .${$}
	rm .${$} &> /dev/null
	if !(rm -f Data/.locked &> /dev/null); then
        	{
                	exit 1
                 } 
        fi

	echo "Done cleanup ... quitting."
	exit 1
}
#THE DIAGNOSTIC DATA (DIAG) ROUTINE TAKES THE DATA STREAM FROM THE TECO 43I-TLE
#AND TESTS FOR THE RECOGNITION OF KEY WORDS IN EACH LINE OF OUTPUT.
#IF THE KEY WORD IS DETECTED ON THAT LINE, A TEST IS PERFORMED. 
#IF THE TEST SUGGESTS THAT AN ERROR CONDITION EXISTS BASED UPON THE ALLOWABLE
#RANGES SPECIFIED BY THE ARB CHECKSHEET, THE OFFENDING LINE IS WRITTEN OUT 
#TO A FILE IN THE Data DIRECTORY. THE NAME OF THE DESTINATION FILE IS
#errors{HH}. THE FILES CAN THEN BE PARSED AND UTILIZED BY ANY ALERT PROGRAM?DAEMON.
diag()
{
this_name=$(cat resources/TECO43iTLE_drv/.usr$instance | grep -o "\-r [A-Za-z0-9]*" | awk '{ print $2 }')
thishour=`date "+%H"`
thisalert="errors${thishour}"
while read DIAGS
do
echo $DIAGS | awk -v name=$this_name '
{                                           
# TEST THE TIME AGAINST DATA LOGGER
if ($1 ~ /Date:/)
   	{
	if (substr($2,4,2)+0 == 23 )  
   		{
   		#test for off an hour or more
   		if (substr($2,1,2) != substr($1,length($1)-12,2))
   		{ print name" Time off by more than an hour! "$0 }
   		#test for off more than 3 minutes. Must add one minute to the 
   		#current minute value since the buffer contains values from the previous minute
   		if (sqrt(((substr($2,4,2)+1) - substr($1,length($1)-9,2))^2) > 3 )
   		{ print name " Time off by more than 2 minutes. " $0 }
   		}
   	}
# TEST THE Sample Flow Rate
# PER George from Thermo, the flow may run commonly lower than .5 lpm.
# He said to monitor for changes in flow rate. Also to calibrate the flow sensor
# For this driver we are setting a basement value of .3 lpm before alerting
# The spec on 1-4 in the manual states .5 or 1.0
if ($1 ~ /Smpfl/ ) 
	{
 	if ( ($2+0) < 0.3)
  		{ print name " Sample flow seems low: " $0}
	if ( ($2+0) > 0.5)
  		{ print name " Sample flow seems high: " $0}
	}
#CHECK OPERATING TEMPERATURE
if ($1 ~ /Intt/ )
		{
		if ( ($2+0) < 15)
				{ print name " The Operating Temp is low: " $0}
		if ( ($2+0) > 35)
				{ print name " The Operating Temp is High: " $0}
		}			
		
}' >> "Data/$thisalert"
done
}
#BEGIN WRITE
#THIS FUNCTION HANDELS READ RIGHT HANDSHAKES BETWEEN VARIOUS DRIVERS
#IN GENERAL, THE DATA IS PLACED IN THE VARIABLE $TIMESTAMP PRIOR TO CALL
#NEXT, IT OPENS THE DATA DIRECTORY AND LOOKS FOR THE .locked FILE
#IF IT EXISTS, IT HANGS OUT UNTIL IT DOESN'T EXIST. AT THAT POINT
#IT CREATES A .locked FILE, AND APPENDS TO THE DATA RECORD.
#FINALLY IT REMOVES THE .locked FILE IT HAS CREATED.
#written by MJV
write()
{
#CONFIRM THAT THERE IS NO HIDDEN FILE CALLED '.locked'
	#PARSE THE .disabled File
        channel_status=`cat ./resources/TECO43iTLE_drv/.disabled$instance`
        #IF THE FILE DOSEN'T EXIT OR IS NOT ACCESIBLE
        #MAKES SURE A VALUE OF 0 IS USED

	while read data
 	do
 	 {      
       		 if [ `expr $channel_status + 0` -eq 1 ]; then
        	if !( sed 's/^/'$timestamp'/g'| sed 's/$/'\-\-DISABLED\-\-'/g'| tee -a "Data/$datafile" | diag); then
        	{
        		echo "GENERAL FAILURE WRITING TO RECORD: $#";
        		cleanup;
       	 	}
        	fi
        else
		if !(echo "$data" | sed 's/^/'$timestamp'/g'| tee -a "Data/$datafile" | diag); then
		{
			echo "GENERAL FAILURE WRITING TO RECORD: $#";
			cleanup;
		}
		fi
	fi
		
		if !(timestamp="" && data=""); then
		{
			echo "GENERAL FAILURE CLEARING WRITE BUFFER: $#";
			exit 1;
		}
		fi	
		if !(rm -f "Data/.locked" &> /dev/null); then
		{
			echo "GENERAL FAILURE REMOVING LOCK: $#";
			exit 1;	
		}
		fi   	
	}
  	done
}

#THIS IS THE ACTUAL COMMUNICATION WITH THE INSTRUMENT
#THE TIMER CONTROL. AT THE BEGINING IT TESTS FOR THE 
#EXISTENCE IF TOGGLE VARRIABLES WHICH ARE UTILIZED BOTH BY
#THE COMM ROUTINE runit() AND THE DIAGNOSTICS DATA ROUTINE
#diag()
runit()
{
#IF THE -d, -C, or -p variable is set to on, then append those parameters
#to the sjinn communication string. 
if [ "$p8n1_val" = "on" ]; then
 	p8n1="-p8n1"
fi
today=`date "+%Y-%d-%m"`
timestamp=$rprt_nm::`date "+%m-%d-%Y_%H:%M"`:::
#THIS IS THE NAME OF THE DATA FILE RIGHT NOW
datafile="$saroad-$today"
#TALK TO THE INSTRUMENT, PRE-APPEND THE TIMESTAMP AND REPORTING NAME TO EACH
#LINE OF OUTPUT AND tee TO THE DATA FILE, then pass to the diag routine.
data_raw=`sjinn -b$bd_rt -d $dvc_prt -s "$cmnd1" -r$rsp_lngth -w$wt_rsp1 $p8n1`
if [[ -f "Data/.locked" ]]; then
	while [[ -f "Data/.locked" ]]; do
		sleep .1 
	done
else 
echo "LOCKED" > "Data/.locked";
echo $data_raw | grep -o "[0-2][0-9]\:[0-9][0-9]\ [0-9]*\-[0-9]*\-[0-9]*" | sed 's/^/Date: /g'>.${$}
echo $data_raw | grep -o "[0-9]\ so2\ [-,.,0-9]*" | awk '{ print $2" "$3 }' >> .${$}
echo $data_raw | grep -o "flags\ [0-9][A-Z][0-9]*" >> .${$}
echo $data_raw | grep -o "loso2\ [-,.,0-9]*" | sed 's/loso2 /43iTLE_loso2=/g' >> .${$}
echo $data_raw | grep -o "pmtv\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "FlshV\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "Intt\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "Rctt\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "PGast\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "Smpfl\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "Pres\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "lo\ avgt\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "[-,.,0-9]\ avgt\ [-,.,0-9]*" | awk '{ print $2" "$3 }' >> .${$}
echo $data_raw | grep -o "SO2bkg\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "[0-9]\ SO2\ coef\ [-,.,0-9]*" | awk '{ print $2" "$3" "$4 }' >> .${$}
echo $data_raw | grep -o "lo\ SO2\ coef\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "[0-9]\ SO2range\ [-,.,0-9]*" | awk '{ print $2" "$3 }' >> .${$}
echo $data_raw | grep -o "Lmpi\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "fltbkg\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "cflow\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "ctmp\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "tamb\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "pamb\ [-,.,0-9]*" >> .${$}
echo $data_raw | grep -o "sum\ [-,.,0-9]*" >> .${$}
#if (data=`cat .${$}`); then
#	{
#		rm .${$}
#	}
#fi

fi
}
#THIS IS THE FUNCTION RUN IN THE EVENT THAT THE REQUIRED PARAMETERS
#ARE NOT ENTERED.
usage()
{
clear
cat << EOF
usage: $0 options
# THIS DRIVER WRITTEN BY MATTHEW VONA ARB FOR THE TECO 43itle SO2 analyzer
# Part Number 103259-00; S/N 0630518483
#FOR QUESTIONS WRITE mailto:mvona@arb.ca.gov
usage: $0 options
The following conditions will cause an entry to be made in a
../../Data/errors[HH] file, where HH stands for the two digit hour. The
'Entry' is simply the offending data received from the instrument.:

	+ TIME (PST) - If off by more than 2 minutes from the data logger
			or more than one hour.
	+ SAMPLE FL -  Less than .4 lpm or greater than .5 lpm 
	+ Intt -       Less than 20 or greater than 30
	+ cflow	-      Converter/Filter flow Less than 0.7 LPM or greater than 0.8 LPM

OPTIONS:
-h	display help
-r	rprt_nm [rn] (Do not include quotes)
-d	dvc_prt [eg, /dev/ttyS0, /dev/ttyUSB1] 
-b	bd_rt [2400,4800,9600,etc.]
-c	cmnd1 (e.g, erec\\r)
-w	wt_rsp1 [seconds]
-l	rsp_lngth [characters]
-s	SAROAD number of the station
-t	[on/off] (OPTIONAL)
-C	[on/off] (OPTIONAL)
-p	[on/off] (OPTIONAL)
-I	instance
Last updated 9/10/2009
EOF
}
#HELP FUNCTION GIVES BACKGROUND ON THIS DRIVER
help_me ()
{
clear
cat .help
exit 0
}
def_opts ()
{
clear
cat .options
}

##CLEAR ALL VARIABLES               
rprt_nm= ; dvc_prt= ; bd_rt= ; cmnd1= ; wt_rsp1= ; bd_rt= ; rsp_lngth= ; izs_val= ;
dvc_prt= ; frqncy= ; dtr= ; ctr= ; p8n1= ; saroad= ; p8n1= ; id_nmbr= ; instance=1 ; 
##INITIALIZE THE BUFFER
return='NOT WRITTEN TO'
##loop through all variables and parameters
##Note that the position of the colon indicates the presence
##of a parameter to collect. The h parameter simply
##returns the help message.

while getopts “hr:s:d:b:c:w:l:f:t:I:p:” OPTION
do
	case $OPTION in
		U)
		upp_flow=$OPTARG
		;;
		L)
		low_flow=$OPTARG
		;;
		s)
		saroad=$OPTARG
		;;
		r)
		rprt_nm=$OPTARG
		;;
		d)
		dvc_prt=$OPTARG
		;;
		b)
		bd_rt=$OPTARG
		;;
		c)
		cmnd1=$OPTARG
		;;
		w)
		wt_rsp1=$OPTARG
		;;
		l)
		rsp_lngth=$OPTARG
		;;
		t)
		dtr_val=$OPTARG
		;;
		p)
		p8n1_val=$OPTARG
		;;
		I)
		instance=$OPTARG
		;;
		h)
		help_me
		exit 1
		;;
		*)
		usage
		exit 1
		;;
	esac
done
#CHECK FOR THE CRITICAL PARAMETERS, IF THEY ARE NOT PRESENT THEN
#RUN THE USAGE FUNCTION WHICH RETURNS THE INSTRUCTIONS FOR PROPER USAGE
#MUST HAVE r n d b c w l s
if [ -z "$rprt_nm" ] || [ -z "$dvc_prt" ] || [ -z "$bd_rt" ] || [ -z "$cmnd1" ] ||
[ -z "$wt_rsp1" ] || [ -z "$rsp_lngth" ] || [ -z "$saroad" ]
	then
		{
		usage
		exit
		}
fi
if [ -z "$instance" ]
then
	{
		echo "This driver must be launched from 1.0 or later. A value for instance was not passed."
	}
fi 
	#INITIALIZED THE RAN VARIABLE. THIS IS USED TO TOGGLE THE TIMER GATE
ran=0
	#TRAP CTRL+C
trap cleanup 1 2 3 6 15
	#SETUP THE OPERATING LOOP
while :
do
	#SET THE SECOND VARIABLE AS THE SECOND VALUE FROM THE DATA STAMP 
second=`date "+%S"`
	#IF THE SECOND VALUE IS LESS THAN 02, BEGIN RUNNING
if [ "$second" -eq "00" ] && [ "$ran" -eq "0" ]; then
	
		#RUN THE RUNIT FUNCTION
			runit
		#RUNIT CREATES A HIDDEN FILE CONTAINING THE TRANSCRIPT OF THE CONVERSATION WITH
		#THE INSTRUMENT. THE NAME OF THE FILE IS THE PROCESS ID OR ".${$}" THIS FILE
		#IS THEN FED TO THE WRITE FUNCTION. IT IS IMPORTANT WITH TECO DRIVERS 
		#THAT runit() RUNS EXACTLY AT THE TOP OF THE MINUTE, INDEPENDENT OF THE WRITE FUNCTION.
			write < .${$}
		#TOGGLE THE RAN VARIABLE SO THAT THE PROCESS WILL NOT REPEAT			
			ran=1
		#WAIT FOR COMPLETION OF THE RUNIT FUNCTION AND THE VARIABLE
		#SET
			sleep 2
	
	#IF THE SECOND VALUE IS GREATER THAT 02, RESET RAN TO 0
	#AND WAIT ONE SECOND BEFORE CHECKING AGAIN
else 
	
		#WAIT ONE SECOND
			sleep .2
		#SET RAN TO 0
			ran=0
	
fi
done;
exit;

